# import os
# import re
# import tkinter as tk
# from tkinter import filedialog, ttk, messagebox
# import threading
# import time
# from datetime import datetime
# import shutil
# import tkinter.font as tkfont
# import ctypes

# class FileSearchTool:
#     def __init__(self, root):
#         """初始化文件搜索工具"""
#         self.root = root
#         self.root.title("高级文件搜索工具")
#         self.root.geometry("1000x650")
#         self.root.minsize(900, 600)
        
#         # 创建线程锁 - 提前初始化
#         self.ui_lock = threading.Lock()
        
#         # 显示初始界面
#         self.show_splash_screen()
        
#         # 启动后台初始化线程
#         self.init_thread = threading.Thread(target=self.initialize_application, daemon=True)
#         self.init_thread.start()
        
#         # 定期检查初始化是否完成
#         self.check_initialization()
    
#     def show_splash_screen(self):
#         """显示启动界面"""
#         self.splash_frame = ttk.Frame(self.root, padding="20")
#         self.splash_frame.pack(fill=tk.BOTH, expand=True)
        
#         # 应用标题
#         title_label = ttk.Label(
#             self.splash_frame, 
#             text="高级文件搜索工具", 
#             font=("SimHei", 24, "bold")
#         )
#         title_label.pack(pady=40)
        
#         # 加载动画
#         self.progress_var = tk.DoubleVar()
#         progress_bar = ttk.Progressbar(
#             self.splash_frame, 
#             orient=tk.HORIZONTAL, 
#             length=300, 
#             mode='indeterminate',
#             variable=self.progress_var
#         )
#         progress_bar.pack(pady=20)
#         progress_bar.start()
        
#         # 状态文本
#         self.status_var = tk.StringVar(value="正在初始化...")
#         status_label = ttk.Label(self.splash_frame, textvariable=self.status_var)
#         status_label.pack(pady=10)
    
#     def initialize_application(self):
#         """在后台线程中执行耗时的初始化操作"""
#         try:
#             # 设置中文字体
#             self.setup_fonts()
            
#             # 更新状态
#             self.status_var.set("正在获取可用驱动器...")
            
#             # 搜索范围选项
#             self.search_scope = tk.StringVar(value="drives")  # 默认使用驱动器搜索
            
#             # 获取可用驱动器（在后台线程中执行）
#             self.drives = self.get_available_drives()
            
#             # 标记初始化完成
#             self.initialized = True
#         except Exception as e:
#             self.initialized = False
#             self.error_message = str(e)
    
#     def check_initialization(self):
#         """检查初始化是否完成"""
#         if hasattr(self, 'initialized') and self.initialized:
#             # 初始化完成，移除启动界面并显示主界面
#             self.splash_frame.destroy()
#             self.create_main_interface()
#         elif hasattr(self, 'error_message'):
#             # 初始化出错，显示错误信息
#             self.splash_frame.destroy()
#             messagebox.showerror("初始化错误", f"应用初始化失败: {self.error_message}")
#         else:
#             # 继续等待
#             self.root.after(100, self.check_initialization)
    
#     def create_main_interface(self):
#         """创建主界面"""
#         # 创建主框架
#         self.main_frame = ttk.Frame(self.root, padding="10")
#         self.main_frame.pack(fill=tk.BOTH, expand=True)
        
#         # 创建搜索参数区域
#         self.create_search_params_frame()
        
#         # 创建结果显示区域
#         self.create_results_frame()
        
#         # 创建进度条
#         self.create_progress_bar()
        
#         # 创建状态栏
#         self.create_status_bar()
        
#         # 变量初始化
#         self.search_thread = None
#         self.stop_event = threading.Event()
#         self.search_in_progress = False
#         self.total_files = 0
#         self.searched_files = 0
#         self.results = []
#         self.search_start_time = None
        
#         # 历史搜索记录
#         self.search_history = []
        
#         # 保存按钮引用
#         self.start_button = None
#         self.stop_button = None
#         self.clear_button = None
    
#     def setup_fonts(self):
#         """配置字体，确保中文正常显示"""
#         font_families = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Microsoft YaHei", "Arial"]
        
#         # 设置默认字体
#         default_font = tkfont.nametofont("TkDefaultFont")
#         text_font = tkfont.nametofont("TkTextFont")
        
#         # 只检查系统中第一个可用的字体
#         for family in font_families:
#             if family in tkfont.families():
#                 default_font.configure(family=family, size=10)
#                 text_font.configure(family=family, size=10)
#                 break
    
#     def create_search_params_frame(self):
#         """创建搜索参数区域"""
#         params_frame = ttk.LabelFrame(self.main_frame, text="搜索参数", padding="10")
#         params_frame.pack(fill=tk.X, pady=(0, 10))
        
#         # 搜索模式选择
#         ttk.Label(params_frame, text="搜索模式:").grid(row=0, column=0, sticky=tk.W, pady=5)
#         self.search_mode = tk.StringVar(value="file_name")
#         ttk.Radiobutton(params_frame, text="文件名", variable=self.search_mode, value="file_name").grid(row=0, column=1, sticky=tk.W, pady=5)
#         ttk.Radiobutton(params_frame, text="文件内容", variable=self.search_mode, value="file_content").grid(row=0, column=2, sticky=tk.W, pady=5)
        
#         # 搜索文本
#         ttk.Label(params_frame, text="搜索文本:").grid(row=1, column=0, sticky=tk.W, pady=5)
#         self.search_text = tk.StringVar()
#         ttk.Entry(params_frame, textvariable=self.search_text, width=50).grid(row=1, column=1, columnspan=2, sticky=tk.W, pady=5)
        
#         # 搜索范围选择
#         ttk.Label(params_frame, text="搜索范围:").grid(row=2, column=0, sticky=tk.W, pady=5)
        
#         # 搜索范围选项
#         scope_frame = ttk.Frame(params_frame)
#         scope_frame.grid(row=2, column=1, sticky=tk.W, pady=5)
        
#         self.select_all_drives_var = tk.BooleanVar(value=True)
#         ttk.Radiobutton(
#             scope_frame, 
#             text="所有驱动器", 
#             variable=self.search_scope, 
#             value="drives", 
#             command=lambda: [self.update_search_scope(), self.select_all_drives(self.select_all_drives_var.get())]
#         ).grid(row=0, column=0, sticky=tk.W, padx=5)
        
#         ttk.Radiobutton(
#             scope_frame, 
#             text="特定文件夹", 
#             variable=self.search_scope, 
#             value="folder", 
#             command=self.update_search_scope
#         ).grid(row=0, column=1, sticky=tk.W, padx=5)
        
#         # 全选/取消全选按钮
#         self.select_all_checkbox = ttk.Checkbutton(
#             params_frame, 
#             text="全选/取消全选", 
#             variable=self.select_all_drives_var,
#             command=lambda: self.select_all_drives(self.select_all_drives_var.get())
#         )
#         self.select_all_checkbox.grid(row=2, column=2, sticky=tk.E, pady=5)
        
#         # 驱动器选择
#         self.drives_frame = ttk.LabelFrame(params_frame, text="驱动器选择", padding="10")
#         self.drives_frame.grid(row=3, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
#         self.drive_vars = {}
#         col = 0
#         max_cols = 4
#         for drive in self.drives:
#             var = tk.BooleanVar(value=False)
#             if drive == "C:\\":  # 默认选中C盘
#                 var.set(True)
#             self.drive_vars[drive] = var
#             ttk.Checkbutton(self.drives_frame, text=drive, variable=var).grid(row=col // max_cols, column=col % max_cols, padx=5, pady=5)
#             col += 1
        
#         # 特定文件夹选择
#         self.folder_frame = ttk.LabelFrame(params_frame, text="特定文件夹", padding="10")
#         self.folder_frame.grid(row=3, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
#         self.selected_folder = tk.StringVar()
#         ttk.Entry(self.folder_frame, textvariable=self.selected_folder, width=60).grid(row=0, column=0, sticky=tk.W, pady=5)
#         ttk.Button(self.folder_frame, text="浏览...", command=self.browse_folder).grid(row=0, column=1, sticky=tk.W, padx=5, pady=5)
        
#         # 初始时隐藏文件夹选择框
#         self.folder_frame.grid_remove()
        
#         # 高级选项
#         advanced_frame = ttk.LabelFrame(params_frame, text="高级选项", padding="10")
#         advanced_frame.grid(row=4, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
#         # 包含子目录
#         self.include_subdirs = tk.BooleanVar(value=True)
#         ttk.Checkbutton(advanced_frame, text="包含子目录", variable=self.include_subdirs).grid(row=0, column=0, sticky=tk.W, pady=5)
        
#         # 区分大小写
#         self.case_sensitive = tk.BooleanVar(value=False)
#         ttk.Checkbutton(advanced_frame, text="区分大小写", variable=self.case_sensitive).grid(row=0, column=1, sticky=tk.W, pady=5)
        
#         # 使用正则表达式
#         self.use_regex = tk.BooleanVar(value=False)
#         ttk.Checkbutton(advanced_frame, text="使用正则表达式", variable=self.use_regex).grid(row=0, column=2, sticky=tk.W, pady=5)
        
#         # 文件类型过滤
#         ttk.Label(advanced_frame, text="文件类型过滤 (用逗号分隔, 如: txt,py):").grid(row=1, column=0, sticky=tk.W, pady=5)
#         self.file_types = tk.StringVar()
#         ttk.Entry(advanced_frame, textvariable=self.file_types, width=30).grid(row=1, column=1, sticky=tk.W, pady=5)
        
#         # 搜索历史
#         history_frame = ttk.LabelFrame(params_frame, text="搜索历史", padding="10")
#         history_frame.grid(row=5, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
#         self.history_listbox = tk.Listbox(history_frame, width=70, height=2)
#         self.history_listbox.grid(row=0, column=0, sticky=tk.W+tk.E, pady=5)
#         self.history_listbox.bind('<Double-1>', self.load_search_history)
        
#         scrollbar = ttk.Scrollbar(history_frame, orient=tk.HORIZONTAL, command=self.history_listbox.xview)
#         self.history_listbox.configure(xscrollcommand=scrollbar.set)
#         scrollbar.grid(row=1, column=0, sticky=tk.W+tk.E)
        
#         # 搜索按钮
#         buttons_frame = ttk.Frame(params_frame)
#         buttons_frame.grid(row=6, column=0, columnspan=3, pady=10)
        
#         # 保存按钮引用
#         self.start_button = ttk.Button(buttons_frame, text="开始搜索", command=self.start_search)
#         self.start_button.grid(row=0, column=0, padx=5)
        
#         self.stop_button = ttk.Button(buttons_frame, text="停止搜索", command=self.stop_search, state=tk.DISABLED)
#         self.stop_button.grid(row=0, column=1, padx=5)
        
#         self.clear_button = ttk.Button(buttons_frame, text="清空结果", command=self.clear_results)
#         self.clear_button.grid(row=0, column=2, padx=5)
        
#         # 初始时选中所有驱动器
#         self.select_all_drives(True)
    
#     def select_all_drives(self, select=True):
#         """全选或取消全选所有驱动器"""
#         with self.ui_lock:
#             for drive, var in self.drive_vars.items():
#                 var.set(select)
#             self.select_all_drives_var.set(select)
    
#     def update_search_scope(self):
#         """更新搜索范围显示"""
#         if self.search_scope.get() == "drives":
#             self.drives_frame.grid()
#             self.folder_frame.grid_remove()
#         else:
#             self.drives_frame.grid_remove()
#             self.folder_frame.grid()
    
#     def browse_folder(self):
#         """浏览并选择文件夹"""
#         directory = filedialog.askdirectory()
#         if directory:
#             self.selected_folder.set(directory)
    
#     def create_results_frame(self):
#         """创建结果显示区域"""
#         results_frame = ttk.LabelFrame(self.main_frame, text="搜索结果", padding="10")
#         results_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
#         # 创建表格
#         columns = ("path", "size", "modified", "line", "content")
#         self.result_tree = ttk.Treeview(results_frame, columns=columns, show="headings")
#         self.result_tree.heading("path", text="文件路径")
#         self.result_tree.heading("size", text="大小")
#         self.result_tree.heading("modified", text="修改日期")
#         self.result_tree.heading("line", text="行号")
#         self.result_tree.heading("content", text="内容")
        
#         self.result_tree.column("path", width=300)
#         self.result_tree.column("size", width=80, anchor=tk.CENTER)
#         self.result_tree.column("modified", width=120, anchor=tk.CENTER)
#         self.result_tree.column("line", width=50, anchor=tk.CENTER)
#         self.result_tree.column("content", width=300)
        
#         # 添加滚动条
#         scroll_y = ttk.Scrollbar(results_frame, orient=tk.VERTICAL, command=self.result_tree.yview)
#         scroll_x = ttk.Scrollbar(results_frame, orient=tk.HORIZONTAL, command=self.result_tree.xview)
#         self.result_tree.configure(yscroll=scroll_y.set, xscroll=scroll_x.set)
        
#         scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
#         scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
#         self.result_tree.pack(fill=tk.BOTH, expand=True)
        
#         # 右键菜单
#         self.create_context_menu()
        
#         # 双击打开文件
#         self.result_tree.bind("<Double-1>", self.open_file)
    
#     def create_context_menu(self):
#         """创建右键菜单"""
#         self.context_menu = tk.Menu(self.root, tearoff=0)
#         self.context_menu.add_command(label="打开文件", command=self.open_file)
#         self.context_menu.add_command(label="打开文件位置", command=self.open_file_location)
#         self.context_menu.add_command(label="删除文件", command=self.delete_file)
#         self.context_menu.add_separator()
#         self.context_menu.add_command(label="复制文件路径", command=self.copy_file_path)
        
#         # 绑定右键菜单
#         self.result_tree.bind("<Button-3>", self.show_context_menu)
    
#     def show_context_menu(self, event):
#         """显示右键菜单"""
#         # 确保点击在项目上
#         item = self.result_tree.identify_row(event.y)
#         if item:
#             self.result_tree.selection_set(item)
#             self.context_menu.post(event.x_root, event.y_root)
    
#     def create_progress_bar(self):
#         """创建进度条"""
#         progress_frame = ttk.Frame(self.main_frame)
#         progress_frame.pack(fill=tk.X, pady=(0, 5))
        
#         self.progress_var = tk.DoubleVar(value=0)
#         self.progress_bar = ttk.Progressbar(
#             progress_frame, 
#             orient=tk.HORIZONTAL, 
#             length=100, 
#             mode='determinate',
#             variable=self.progress_var
#         )
#         self.progress_bar.pack(fill=tk.X)
        
#         # 初始时隐藏进度条
#         self.progress_bar.pack_forget()
    
#     def create_status_bar(self):
#         """创建状态栏"""
#         self.status_bar = ttk.Label(self.root, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
#         self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
#     def get_available_drives(self):
#         """获取系统中所有可用的驱动器 - 优化版本"""
#         try:
#             # 使用ctypes获取驱动器信息，效率更高
#             drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
#             drives = []
#             for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
#                 if drive_bitmask & 1:
#                     drive = f"{letter}:\\"
#                     # 检查驱动器类型，只保留可移动磁盘、本地磁盘和网络驱动器
#                     drive_type = ctypes.cdll.kernel32.GetDriveTypeW(drive)
#                     if drive_type in (2, 3, 4):  # 可移动磁盘、本地磁盘、网络驱动器
#                         drives.append(drive)
#                 drive_bitmask >>= 1
#             return drives
#         except:
#             # 作为最后的备选，使用原始方法
#             import string
#             drives = []
#             for letter in string.ascii_uppercase:
#                 drive = f"{letter}:\\"
#                 # 检查驱动器是否存在
#                 try:
#                     # 使用os.listdir而不是os.path.exists，因为它更快
#                     os.listdir(drive)
#                     drives.append(drive)
#                 except:
#                     continue
#             return drives
    
#     def start_search(self):
#         """开始搜索"""
#         # 检查搜索文本
#         search_text = self.search_text.get().strip()
        
#         if not search_text:
#             messagebox.showwarning("警告", "请输入搜索文本")
#             return
        
#         # 获取搜索位置
#         search_locations = []
        
#         if self.search_scope.get() == "drives":
#             # 获取选中的驱动器
#             selected_drives = [drive for drive, var in self.drive_vars.items() if var.get()]
            
#             if not selected_drives:
#                 messagebox.showwarning("警告", "请选择至少一个搜索驱动器")
#                 return
                
#             search_locations = selected_drives
#         else:
#             # 获取选中的文件夹
#             folder_path = self.selected_folder.get().strip()
            
#             if not folder_path or not os.path.exists(folder_path):
#                 messagebox.showwarning("警告", "请选择有效的搜索文件夹")
#                 return
                
#             search_locations = [folder_path]
        
#         # 清空之前的结果
#         self.clear_results()
        
#         # 显示进度条并重置
#         with self.ui_lock:
#             self.progress_bar.pack(fill=tk.X)
#             self.progress_var.set(0)
        
#         # 更新状态
#         self.search_in_progress = True
#         self.status_bar.config(text="准备搜索...")
#         self.total_files = 0
#         self.searched_files = 0
#         self.results = []
#         self.search_start_time = datetime.now()
        
#         # 更新按钮状态
#         if self.start_button:
#             self.start_button.config(state=tk.DISABLED)
#         if self.stop_button:
#             self.stop_button.config(state=tk.NORMAL)
        
#         # 重置停止事件
#         self.stop_event.clear()
        
#         # 保存搜索历史
#         self.save_search_history()
        
#         # 在新线程中执行搜索
#         self.search_thread = threading.Thread(target=self.perform_search, args=(search_locations,), daemon=True)
#         self.search_thread.start()
    
#     def stop_search(self):
#         """停止搜索"""
#         if self.search_in_progress:
#             self.stop_event.set()
#             self.status_bar.config(text="正在停止搜索...")
    
#     def clear_results(self):
#         """清空搜索结果"""
#         with self.ui_lock:
#             for item in self.result_tree.get_children():
#                 self.result_tree.delete(item)
#             self.results = []
#             self.status_bar.config(text="就绪")
#             self.progress_bar.pack_forget()
#             self.progress_var.set(0)
    
#     def save_search_history(self):
#         """保存搜索历史"""
#         search_text = self.search_text.get().strip()
#         search_mode = self.search_mode.get()
        
#         history_item = f"[{search_mode}] {search_text}"
#         self.search_history.append(history_item)
        
#         # 更新历史列表
#         with self.ui_lock:
#             self.history_listbox.delete(0, tk.END)
#             for item in self.search_history[-5:]:  # 只显示最近5条
#                 self.history_listbox.insert(tk.END, item)
    
#     def load_search_history(self, event):
#         """加载搜索历史"""
#         selection = self.history_listbox.curselection()
#         if selection:
#             history_item = self.history_listbox.get(selection[0])
            
#             # 解析历史项
#             mode_start = history_item.find('[') + 1
#             mode_end = history_item.find(']')
#             search_mode = history_item[mode_start:mode_end]
#             search_text = history_item[mode_end + 2:]
            
#             # 更新搜索参数
#             self.search_mode.set(search_mode)
#             self.search_text.set(search_text)
    
#     def perform_search(self, search_locations):
#         """执行搜索操作"""
#         search_text = self.search_text.get()
#         search_mode = self.search_mode.get()
#         include_subdirs = self.include_subdirs.get()
#         case_sensitive = self.case_sensitive.get()
#         use_regex = self.use_regex.get()
#         file_types = [t.strip() for t in self.file_types.get().split(',') if t.strip()]
        
#         # 处理搜索文本
#         if not case_sensitive and not use_regex:
#             search_text = search_text.lower()
        
#         # 编译正则表达式（如果需要）
#         regex_pattern = None
#         if use_regex:
#             try:
#                 flags = 0 if case_sensitive else re.IGNORECASE
#                 regex_pattern = re.compile(search_text, flags)
#             except re.error as e:
#                 self.root.after(0, lambda: messagebox.showerror("正则表达式错误", f"无效的正则表达式: {str(e)}"))
#                 self.search_complete()
#                 return
        
#         # 计算要搜索的文件总数
#         self.total_files = self.count_files_to_search(search_locations, include_subdirs, file_types)
        
#         # 如果没有文件可搜索，直接完成
#         if self.total_files == 0:
#             self.root.after(0, lambda: messagebox.showinfo("搜索结果", "没有找到符合条件的文件"))
#             self.search_complete()
#             return
        
#         # 执行搜索
#         for location in search_locations:
#             if self.stop_event.is_set():
#                 break
            
#             if os.path.isfile(location):
#                 # 直接搜索单个文件
#                 self.search_file(location, search_text, search_mode, case_sensitive, use_regex, regex_pattern)
#                 self.searched_files += 1
#                 self.update_status()
#             else:
#                 # 搜索目录
#                 self.search_directory(location, search_text, search_mode, case_sensitive, use_regex, regex_pattern, include_subdirs, file_types)
        
#         self.search_complete()
    
#     def count_files_to_search(self, locations, include_subdirs, file_types):
#         """计算要搜索的文件总数"""
#         count = 0
#         for location in locations:
#             if os.path.isfile(location):
#                 count += 1
#             else:
#                 for root, _, files in os.walk(location):
#                     for file in files:
#                         # 检查文件类型过滤
#                         if file_types:
#                             ext = os.path.splitext(file)[1][1:].lower()
#                             if ext not in file_types:
#                                 continue
                        
#                         count += 1
                    
#                     if not include_subdirs:
#                         break
#         return count
    
#     def search_directory(self, directory, search_text, search_mode, case_sensitive, use_regex, regex_pattern, include_subdirs, file_types):
#         """搜索目录中的文件"""
#         try:
#             for root, _, files in os.walk(directory):
#                 if self.stop_event.is_set():
#                     return
                
#                 for file in files:
#                     if self.stop_event.is_set():
#                         return
                    
#                     # 检查文件类型过滤
#                     if file_types:
#                         ext = os.path.splitext(file)[1][1:].lower()
#                         if ext not in file_types:
#                             continue
                    
#                     file_path = os.path.join(root, file)
#                     self.search_file(file_path, search_text, search_mode, case_sensitive, use_regex, regex_pattern)
#                     self.searched_files += 1
                    
#                     # 每搜索50个文件更新一次进度，减少UI更新频率
#                     if self.searched_files % 50 == 0:
#                         self.update_status()
                
#                 if not include_subdirs:
#                     break
#         except Exception as e:
#             # 忽略无法访问的目录
#             pass
    
#     def search_file(self, file_path, search_text, search_mode, case_sensitive, use_regex, regex_pattern):
#         """搜索单个文件"""
#         try:
#             if search_mode == "file_name":
#                 # 搜索文件名
#                 file_name = os.path.basename(file_path)
#                 if use_regex:
#                     if regex_pattern.search(file_name):
#                         self.add_result(file_path, 0, "")
#                 else:
#                     compare_text = file_name if case_sensitive else file_name.lower()
#                     if search_text in compare_text:
#                         self.add_result(file_path, 0, "")
#             else:
#                 # 搜索文件内容
#                 try:
#                     with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
#                         for line_num, line in enumerate(f, 1):
#                             if self.stop_event.is_set():
#                                 break
                            
#                             if use_regex:
#                                 if regex_pattern.search(line):
#                                     self.add_result(file_path, line_num, line.strip())
#                             else:
#                                 compare_line = line if case_sensitive else line.lower()
#                                 if search_text in compare_line:
#                                     self.add_result(file_path, line_num, line.strip())
#                 except UnicodeDecodeError:
#                     # 尝试其他编码
#                     try:
#                         with open(file_path, 'r', encoding='latin-1') as f:
#                             for line_num, line in enumerate(f, 1):
#                                 if self.stop_event.is_set():
#                                     break
                                
#                                 if use_regex:
#                                     if regex_pattern.search(line):
#                                         self.add_result(file_path, line_num, line.strip())
#                                 else:
#                                     compare_line = line if case_sensitive else line.lower()
#                                     if search_text in compare_line:
#                                         self.add_result(file_path, line_num, line.strip())
#                     except:
#                         # 无法打开文件
#                         pass
#         except Exception as e:
#             # 忽略无法打开的文件
#             pass
    
#     def add_result(self, file_path, line_num, content):
#         """添加搜索结果"""
#         try:
#             # 获取文件大小和修改日期
#             file_stats = os.stat(file_path)
#             file_size = self.format_size(file_stats.st_size)
#             modified_time = datetime.fromtimestamp(file_stats.st_mtime).strftime("%Y-%m-%d %H:%M:%S")
            
#             self.root.after(0, lambda: self.result_tree.insert("", tk.END, values=(file_path, file_size, modified_time, line_num, content)))
#             with self.ui_lock:
#                 self.results.append((file_path, line_num, content))
#         except:
#             # 如果获取文件信息失败，仍添加结果
#             self.root.after(0, lambda: self.result_tree.insert("", tk.END, values=(file_path, "未知", "未知", line_num, content)))
#             with self.ui_lock:
#                 self.results.append((file_path, line_num, content))
    
#     def format_size(self, size_bytes):
#         """格式化文件大小显示"""
#         if size_bytes < 1024:
#             return f"{size_bytes} B"
#         elif size_bytes < 1024 * 1024:
#             return f"{size_bytes/1024:.1f} KB"
#         elif size_bytes < 1024 * 1024 * 1024:
#             return f"{size_bytes/(1024*1024):.1f} MB"
#         else:
#             return f"{size_bytes/(1024*1024*1024):.1f} GB"
    
#     def update_status(self):
#         """更新状态栏信息和进度条"""
#         if self.total_files > 0:
#             progress = min(100.0, (self.searched_files / self.total_files) * 100)
#             elapsed_time = (datetime.now() - self.search_start_time).total_seconds()
#             status_text = f"搜索中... 已搜索: {self.searched_files}/{self.total_files} 文件 ({progress:.1f}%), 找到 {len(self.results)} 个结果，耗时: {elapsed_time:.1f} 秒"
            
#             # 在主线程中更新UI
#             self.root.after(0, lambda: self._update_ui(status_text, progress))
    
#     def _update_ui(self, status_text, progress):
#         """实际更新UI的方法"""
#         with self.ui_lock:
#             self.status_bar.config(text=status_text)
#             self.progress_var.set(progress)
    
#     def search_complete(self):
#         """搜索完成后的处理"""
#         self.search_in_progress = False
        
#         # 计算总时间
#         total_time = (datetime.now() - self.search_start_time).total_seconds()
        
#         # 更新状态栏
#         if self.stop_event.is_set():
#             status_text = f"搜索已取消! 共搜索 {self.searched_files} 个文件，找到 {len(self.results)} 个结果，耗时: {total_time:.1f} 秒"
#         else:
#             status_text = f"搜索完成! 共搜索 {self.searched_files} 个文件，找到 {len(self.results)} 个结果，耗时: {total_time:.1f} 秒"
        
#         # 在主线程中更新UI
#         self.root.after(0, lambda: self._search_complete_ui(status_text))
    
#     def _search_complete_ui(self, status_text):
#         """实际更新搜索完成UI的方法"""
#         with self.ui_lock:
#             self.status_bar.config(text=status_text)
            
#             # 更新按钮状态
#             if self.start_button:
#                 self.start_button.config(state=tk.NORMAL)
#             if self.stop_button:
#                 self.stop_button.config(state=tk.DISABLED)
            
#             # 隐藏进度条
#             self.root.after(3000, lambda: self.progress_bar.pack_forget() if not self.search_in_progress else None)
    
#     def open_file(self, event=None):
#         """打开文件"""
#         try:
#             # 获取选中的项
#             selected_items = self.result_tree.selection()
#             if not selected_items:
#                 return
                
#             for item in selected_items:
#                 file_path = self.result_tree.item(item, "values")[0]
                
#                 # 检查文件是否存在
#                 if not os.path.exists(file_path):
#                     messagebox.showwarning("警告", f"文件不存在: {file_path}")
#                     continue
                
#                 # 在Windows上打开文件
#                 os.startfile(file_path)
#         except Exception as e:
#             messagebox.showerror("错误", f"无法打开文件: {str(e)}")
    
#     def open_file_location(self):
#         """打开文件所在位置"""
#         try:
#             # 获取选中的项
#             selected_items = self.result_tree.selection()
#             if not selected_items:
#                 return
                
#             for item in selected_items:
#                 file_path = self.result_tree.item(item, "values")[0]
                
#                 # 检查文件是否存在
#                 if not os.path.exists(file_path):
#                     messagebox.showwarning("警告", f"文件不存在: {file_path}")
#                     continue
                
#                 directory = os.path.dirname(file_path)
                
#                 # 在Windows上打开文件所在目录
#                 os.startfile(directory)
#         except Exception as e:
#             messagebox.showerror("错误", f"无法打开文件位置: {str(e)}")
    
#     def delete_file(self):
#         """删除文件"""
#         try:
#             # 获取选中的项
#             selected_items = self.result_tree.selection()
#             if not selected_items:
#                 return
                
#             # 确认删除
#             count = len(selected_items)
#             if count == 1:
#                 file_path = self.result_tree.item(selected_items[0], "values")[0]
#                 message = f"确定要删除以下文件吗?\n\n{file_path}"
#             else:
#                 message = f"确定要删除选中的 {count} 个文件吗?"
                
#             confirm = messagebox.askyesno("确认删除", message)
#             if not confirm:
#                 return
                
#             deleted_count = 0
#             for item in selected_items:
#                 file_path = self.result_tree.item(item, "values")[0]
                
#                 # 检查文件是否存在
#                 if not os.path.exists(file_path):
#                     messagebox.showwarning("警告", f"文件不存在: {file_path}")
#                     continue
                
#                 try:
#                     # 删除文件
#                     os.remove(file_path)
#                     deleted_count += 1
                    
#                     # 从结果中移除
#                     self.result_tree.delete(item)
#                 except Exception as e:
#                     messagebox.showerror("错误", f"无法删除文件: {file_path}\n\n{str(e)}")
            
#             if deleted_count > 0:
#                 messagebox.showinfo("操作完成", f"成功删除 {deleted_count} 个文件")
#                 self.status_bar.config(text=f"已删除 {deleted_count} 个文件")
#         except Exception as e:
#             messagebox.showerror("错误", f"删除文件时出错: {str(e)}")
    
#     def copy_file_path(self):
#         """复制文件路径到剪贴板"""
#         try:
#             # 获取选中的项
#             selected_items = self.result_tree.selection()
#             if not selected_items:
#                 return
                
#             # 复制路径
#             paths = []
#             for item in selected_items:
#                 file_path = self.result_tree.item(item, "values")[0]
#                 paths.append(file_path)
                
#             # 复制到剪贴板
#             self.root.clipboard_clear()
#             self.root.clipboard_append("\n".join(paths))
            
#             messagebox.showinfo("操作完成", f"已复制 {len(paths)} 个文件路径到剪贴板")
#         except Exception as e:
#             messagebox.showerror("错误", f"复制文件路径时出错: {str(e)}")

# if __name__ == "__main__":
#     # 确保中文显示正常
#     import matplotlib
#     matplotlib.use('TkAgg')
    
#     root = tk.Tk()
#     app = FileSearchTool(root)
#     root.mainloop()  
# 
# 







import os
import re
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import threading
import time
from datetime import datetime
import shutil
import tkinter.font as tkfont
import ctypes

class FileSearchTool:
    def __init__(self, root):
        """初始化文件搜索工具"""
        self.root = root
        self.root.title("高级文件搜索工具")
        self.root.geometry("1000x650")
        self.root.minsize(900, 600)
        
        # 创建线程锁
        self.ui_lock = threading.Lock()
        
        # 显示初始界面
        self.show_splash_screen()
        
        # 启动后台初始化线程
        self.init_thread = threading.Thread(target=self.initialize_application, daemon=True)
        self.init_thread.start()
        
        # 定期检查初始化是否完成
        self.check_initialization()
    
    def show_splash_screen(self):
        """显示启动界面"""
        self.splash_frame = ttk.Frame(self.root, padding="20")
        self.splash_frame.pack(fill=tk.BOTH, expand=True)
        
        # 应用标题
        title_label = ttk.Label(
            self.splash_frame, 
            text="高级文件搜索工具", 
            font=("SimHei", 24, "bold")
        )
        title_label.pack(pady=40)
        
        # 加载动画
        self.progress_var = tk.DoubleVar()
        progress_bar = ttk.Progressbar(
            self.splash_frame, 
            orient=tk.HORIZONTAL, 
            length=300, 
            mode='indeterminate',
            variable=self.progress_var
        )
        progress_bar.pack(pady=20)
        progress_bar.start()
        
        # 状态文本
        self.status_var = tk.StringVar(value="正在初始化...")
        status_label = ttk.Label(self.splash_frame, textvariable=self.status_var)
        status_label.pack(pady=10)
    
    def initialize_application(self):
        """在后台线程中执行耗时的初始化操作"""
        try:
            # 设置中文字体
            self.setup_fonts()
            
            # 更新状态
            self.status_var.set("正在获取可用驱动器...")
            
            # 搜索范围选项
            self.search_scope = tk.StringVar(value="drives")  # 默认使用驱动器搜索
            
            # 获取可用驱动器（在后台线程中执行）
            self.drives = self.get_available_drives()
            
            # 标记初始化完成
            self.initialized = True
        except Exception as e:
            self.initialized = False
            self.error_message = str(e)
    
    def check_initialization(self):
        """检查初始化是否完成"""
        if hasattr(self, 'initialized') and self.initialized:
            # 初始化完成，移除启动界面并显示主界面
            self.splash_frame.destroy()
            self.create_main_interface()
        elif hasattr(self, 'error_message'):
            # 初始化出错，显示错误信息
            self.splash_frame.destroy()
            messagebox.showerror("初始化错误", f"应用初始化失败: {self.error_message}")
        else:
            # 继续等待
            self.root.after(100, self.check_initialization)
    
    def create_main_interface(self):
        """创建主界面"""
        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建搜索参数区域
        self.create_search_params_frame()
        
        # 创建结果显示区域
        self.create_results_frame()
        
        # 创建增强的进度显示区域
        self.create_enhanced_progress_display()
        
        # 创建状态栏
        self.create_status_bar()
        
        # 变量初始化
        self.search_thread = None
        self.stop_event = threading.Event()
        self.search_in_progress = False
        self.total_files = 0
        self.searched_files = 0
        self.results = []
        self.search_start_time = None
        
        # 历史搜索记录
        self.search_history = []
        
        # 保存按钮引用
        self.start_button = None
        self.stop_button = None
        self.clear_button = None
    
    def setup_fonts(self):
        """配置字体，确保中文正常显示"""
        font_families = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Microsoft YaHei", "Arial"]
        
        # 设置默认字体
        default_font = tkfont.nametofont("TkDefaultFont")
        text_font = tkfont.nametofont("TkTextFont")
        
        # 只检查系统中第一个可用的字体
        for family in font_families:
            if family in tkfont.families():
                default_font.configure(family=family, size=10)
                text_font.configure(family=family, size=10)
                break
    
    def create_search_params_frame(self):
        """创建搜索参数区域"""
        params_frame = ttk.LabelFrame(self.main_frame, text="搜索参数", padding="10")
        params_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 搜索模式选择
        ttk.Label(params_frame, text="搜索模式:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.search_mode = tk.StringVar(value="file_name")
        ttk.Radiobutton(params_frame, text="文件名", variable=self.search_mode, value="file_name").grid(row=0, column=1, sticky=tk.W, pady=5)
        ttk.Radiobutton(params_frame, text="文件内容", variable=self.search_mode, value="file_content").grid(row=0, column=2, sticky=tk.W, pady=5)
        
        # 搜索文本
        ttk.Label(params_frame, text="搜索文本:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.search_text = tk.StringVar()
        ttk.Entry(params_frame, textvariable=self.search_text, width=50).grid(row=1, column=1, columnspan=2, sticky=tk.W, pady=5)
        
        # 搜索范围选择
        ttk.Label(params_frame, text="搜索范围:").grid(row=2, column=0, sticky=tk.W, pady=5)
        
        # 搜索范围选项
        scope_frame = ttk.Frame(params_frame)
        scope_frame.grid(row=2, column=1, sticky=tk.W, pady=5)
        
        self.select_all_drives_var = tk.BooleanVar(value=True)
        ttk.Radiobutton(
            scope_frame, 
            text="所有驱动器", 
            variable=self.search_scope, 
            value="drives", 
            command=lambda: [self.update_search_scope(), self.select_all_drives(self.select_all_drives_var.get())]
        ).grid(row=0, column=0, sticky=tk.W, padx=5)
        
        ttk.Radiobutton(
            scope_frame, 
            text="特定文件夹", 
            variable=self.search_scope, 
            value="folder", 
            command=self.update_search_scope
        ).grid(row=0, column=1, sticky=tk.W, padx=5)
        
        # 全选/取消全选按钮
        self.select_all_checkbox = ttk.Checkbutton(
            params_frame, 
            text="全选/取消全选", 
            variable=self.select_all_drives_var,
            command=lambda: self.select_all_drives(self.select_all_drives_var.get())
        )
        self.select_all_checkbox.grid(row=2, column=2, sticky=tk.E, pady=5)
        
        # 驱动器选择
        self.drives_frame = ttk.LabelFrame(params_frame, text="驱动器选择", padding="10")
        self.drives_frame.grid(row=3, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
        self.drive_vars = {}
        col = 0
        max_cols = 4
        for drive in self.drives:
            var = tk.BooleanVar(value=False)
            if drive == "C:\\":  # 默认选中C盘
                var.set(True)
            self.drive_vars[drive] = var
            ttk.Checkbutton(self.drives_frame, text=drive, variable=var).grid(row=col // max_cols, column=col % max_cols, padx=5, pady=5)
            col += 1
        
        # 特定文件夹选择
        self.folder_frame = ttk.LabelFrame(params_frame, text="特定文件夹", padding="10")
        self.folder_frame.grid(row=3, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
        self.selected_folder = tk.StringVar()
        ttk.Entry(self.folder_frame, textvariable=self.selected_folder, width=60).grid(row=0, column=0, sticky=tk.W, pady=5)
        ttk.Button(self.folder_frame, text="浏览...", command=self.browse_folder).grid(row=0, column=1, sticky=tk.W, padx=5, pady=5)
        
        # 初始时隐藏文件夹选择框
        self.folder_frame.grid_remove()
        
        # 高级选项
        advanced_frame = ttk.LabelFrame(params_frame, text="高级选项", padding="10")
        advanced_frame.grid(row=4, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
        # 包含子目录
        self.include_subdirs = tk.BooleanVar(value=True)
        ttk.Checkbutton(advanced_frame, text="包含子目录", variable=self.include_subdirs).grid(row=0, column=0, sticky=tk.W, pady=5)
        
        # 区分大小写
        self.case_sensitive = tk.BooleanVar(value=False)
        ttk.Checkbutton(advanced_frame, text="区分大小写", variable=self.case_sensitive).grid(row=0, column=1, sticky=tk.W, pady=5)
        
        # 使用正则表达式
        self.use_regex = tk.BooleanVar(value=False)
        ttk.Checkbutton(advanced_frame, text="使用正则表达式", variable=self.use_regex).grid(row=0, column=2, sticky=tk.W, pady=5)
        
        # 文件类型过滤
        ttk.Label(advanced_frame, text="文件类型过滤 (用逗号分隔, 如: txt,py):").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.file_types = tk.StringVar()
        ttk.Entry(advanced_frame, textvariable=self.file_types, width=30).grid(row=1, column=1, sticky=tk.W, pady=5)
        
        # 搜索历史
        history_frame = ttk.LabelFrame(params_frame, text="搜索历史", padding="10")
        history_frame.grid(row=5, column=0, columnspan=3, sticky=tk.W+tk.E, pady=10)
        
        self.history_listbox = tk.Listbox(history_frame, width=70, height=2)
        self.history_listbox.grid(row=0, column=0, sticky=tk.W+tk.E, pady=5)
        self.history_listbox.bind('<Double-1>', self.load_search_history)
        
        scrollbar = ttk.Scrollbar(history_frame, orient=tk.HORIZONTAL, command=self.history_listbox.xview)
        self.history_listbox.configure(xscrollcommand=scrollbar.set)
        scrollbar.grid(row=1, column=0, sticky=tk.W+tk.E)
        
        # 搜索按钮
        buttons_frame = ttk.Frame(params_frame)
        buttons_frame.grid(row=6, column=0, columnspan=3, pady=10)
        
        # 保存按钮引用
        self.start_button = ttk.Button(buttons_frame, text="开始搜索", command=self.start_search)
        self.start_button.grid(row=0, column=0, padx=5)
        
        self.stop_button = ttk.Button(buttons_frame, text="停止搜索", command=self.stop_search, state=tk.DISABLED)
        self.stop_button.grid(row=0, column=1, padx=5)
        
        self.clear_button = ttk.Button(buttons_frame, text="清空结果", command=self.clear_results)
        self.clear_button.grid(row=0, column=2, padx=5)
        
        # 初始时选中所有驱动器
        self.select_all_drives(True)
    
    def select_all_drives(self, select=True):
        """全选或取消全选所有驱动器"""
        with self.ui_lock:
            for drive, var in self.drive_vars.items():
                var.set(select)
            self.select_all_drives_var.set(select)
    
    def update_search_scope(self):
        """更新搜索范围显示"""
        if self.search_scope.get() == "drives":
            self.drives_frame.grid()
            self.folder_frame.grid_remove()
        else:
            self.drives_frame.grid_remove()
            self.folder_frame.grid()
    
    def browse_folder(self):
        """浏览并选择文件夹"""
        directory = filedialog.askdirectory()
        if directory:
            self.selected_folder.set(directory)
    
    def create_results_frame(self):
        """创建结果显示区域"""
        results_frame = ttk.LabelFrame(self.main_frame, text="搜索结果", padding="10")
        results_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        # 创建表格
        columns = ("path", "size", "modified", "line", "content")
        self.result_tree = ttk.Treeview(results_frame, columns=columns, show="headings")
        self.result_tree.heading("path", text="文件路径")
        self.result_tree.heading("size", text="大小")
        self.result_tree.heading("modified", text="修改日期")
        self.result_tree.heading("line", text="行号")
        self.result_tree.heading("content", text="内容")
        
        self.result_tree.column("path", width=300)
        self.result_tree.column("size", width=80, anchor=tk.CENTER)
        self.result_tree.column("modified", width=120, anchor=tk.CENTER)
        self.result_tree.column("line", width=50, anchor=tk.CENTER)
        self.result_tree.column("content", width=300)
        
        # 添加滚动条
        scroll_y = ttk.Scrollbar(results_frame, orient=tk.VERTICAL, command=self.result_tree.yview)
        scroll_x = ttk.Scrollbar(results_frame, orient=tk.HORIZONTAL, command=self.result_tree.xview)
        self.result_tree.configure(yscroll=scroll_y.set, xscroll=scroll_x.set)
        
        scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
        scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
        self.result_tree.pack(fill=tk.BOTH, expand=True)
        
        # 右键菜单
        self.create_context_menu()
        
        # 双击打开文件
        self.result_tree.bind("<Double-1>", self.open_file)
        
        # 新增：一键清空结果按钮
        clear_frame = ttk.Frame(results_frame)
        clear_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=5)
        
        self.clear_all_button = ttk.Button(
            clear_frame, 
            text="一键清空所有结果", 
            command=self.clear_all_results,
            style='Accent.TButton'  # 使用强调样式
        )
        self.clear_all_button.pack(side=tk.RIGHT, padx=5)
    
    def create_context_menu(self):
        """创建右键菜单"""
        self.context_menu = tk.Menu(self.root, tearoff=0)
        self.context_menu.add_command(label="打开文件", command=self.open_file)
        self.context_menu.add_command(label="打开文件位置", command=self.open_file_location)
        self.context_menu.add_command(label="删除文件", command=self.delete_file)
        self.context_menu.add_separator()
        self.context_menu.add_command(label="复制文件路径", command=self.copy_file_path)
        
        # 绑定右键菜单
        self.result_tree.bind("<Button-3>", self.show_context_menu)
    
    def show_context_menu(self, event):
        """显示右键菜单"""
        # 确保点击在项目上
        item = self.result_tree.identify_row(event.y)
        if item:
            self.result_tree.selection_set(item)
            self.context_menu.post(event.x_root, event.y_root)
    
    def create_enhanced_progress_display(self):
        """创建增强的进度显示区域"""
        progress_frame = ttk.LabelFrame(self.main_frame, text="搜索进度", padding="10")
        self.progress_frame = progress_frame
        
        # 主进度条
        self.progress_var = tk.DoubleVar(value=0)
        progress_bar = ttk.Progressbar(
            progress_frame, 
            orient=tk.HORIZONTAL, 
            length=100, 
            mode='determinate',
            variable=self.progress_var
        )
        progress_bar.pack(fill=tk.X, pady=(0, 5))
        
        # 详细进度信息
        info_frame = ttk.Frame(progress_frame)
        info_frame.pack(fill=tk.X)
        
        # 已搜索文件数
        self.searched_files_var = tk.StringVar(value="已搜索: 0 个文件")
        ttk.Label(info_frame, textvariable=self.searched_files_var).grid(row=0, column=0, sticky=tk.W, padx=5)
        
        # 搜索速度
        self.search_speed_var = tk.StringVar(value="搜索速度: 0 文件/秒")
        ttk.Label(info_frame, textvariable=self.search_speed_var).grid(row=0, column=1, sticky=tk.W, padx=5)
        
        # 预计剩余时间
        self.estimated_time_var = tk.StringVar(value="预计剩余时间: 计算中...")
        ttk.Label(info_frame, textvariable=self.estimated_time_var).grid(row=0, column=2, sticky=tk.W, padx=5)
        
        # 初始时隐藏进度区域
        progress_frame.pack_forget()
    
    def create_status_bar(self):
        """创建状态栏"""
        self.status_bar = ttk.Label(self.root, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
    def get_available_drives(self):
        """获取系统中所有可用的驱动器 - 优化版本"""
        try:
            # 使用ctypes获取驱动器信息，效率更高
            drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
            drives = []
            for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
                if drive_bitmask & 1:
                    drive = f"{letter}:\\"
                    # 检查驱动器类型，只保留可移动磁盘、本地磁盘和网络驱动器
                    drive_type = ctypes.cdll.kernel32.GetDriveTypeW(drive)
                    if drive_type in (2, 3, 4):  # 可移动磁盘、本地磁盘、网络驱动器
                        drives.append(drive)
                drive_bitmask >>= 1
            return drives
        except:
            # 作为最后的备选，使用原始方法
            import string
            drives = []
            for letter in string.ascii_uppercase:
                drive = f"{letter}:\\"
                # 检查驱动器是否存在
                try:
                    # 使用os.listdir而不是os.path.exists，因为它更快
                    os.listdir(drive)
                    drives.append(drive)
                except:
                    continue
            return drives
    
    def start_search(self):
        """开始搜索"""
        # 检查搜索文本
        search_text = self.search_text.get().strip()
        
        if not search_text:
            messagebox.showwarning("警告", "请输入搜索文本")
            return
        
        # 获取搜索位置
        search_locations = []
        
        if self.search_scope.get() == "drives":
            # 获取选中的驱动器
            selected_drives = [drive for drive, var in self.drive_vars.items() if var.get()]
            
            if not selected_drives:
                messagebox.showwarning("警告", "请选择至少一个搜索驱动器")
                return
                
            search_locations = selected_drives
        else:
            # 获取选中的文件夹
            folder_path = self.selected_folder.get().strip()
            
            if not folder_path or not os.path.exists(folder_path):
                messagebox.showwarning("警告", "请选择有效的搜索文件夹")
                return
                
            search_locations = [folder_path]
        
        # 清空之前的结果
        self.clear_results()
        
        # 显示进度区域并重置
        self.progress_frame.pack(fill=tk.X, pady=(0, 10))
        self.progress_var.set(0)
        self.searched_files_var.set("已搜索: 0 个文件")
        self.search_speed_var.set("搜索速度: 0 文件/秒")
        self.estimated_time_var.set("预计剩余时间: 计算中...")
        
        # 更新状态
        self.search_in_progress = True
        self.status_bar.config(text="准备搜索...")
        self.total_files = 0
        self.searched_files = 0
        self.results = []
        self.search_start_time = datetime.now()
        self.last_update_time = self.search_start_time
        
        # 更新按钮状态
        if self.start_button:
            self.start_button.config(state=tk.DISABLED)
        if self.stop_button:
            self.stop_button.config(state=tk.NORMAL)
        
        # 重置停止事件
        self.stop_event.clear()
        
        # 保存搜索历史
        self.save_search_history()
        
        # 在新线程中执行搜索
        self.search_thread = threading.Thread(target=self.perform_search, args=(search_locations,), daemon=True)
        self.search_thread.start()
    
    def stop_search(self):
        """停止搜索"""
        if self.search_in_progress:
            self.stop_event.set()
            self.status_bar.config(text="正在停止搜索...")
    
    def clear_results(self):
        """清空搜索结果"""
        with self.ui_lock:
            for item in self.result_tree.get_children():
                self.result_tree.delete(item)
            self.results = []
            self.status_bar.config(text="就绪")
            self.progress_frame.pack_forget()
            self.progress_var.set(0)
    
    def clear_all_results(self):
        """一键清空所有结果"""
        if not self.result_tree.get_children():
            messagebox.showinfo("提示", "当前没有搜索结果可清空")
            return
            
        # 确认清空
        if messagebox.askyesno("确认清空", "确定要清空所有搜索结果吗？"):
            self.clear_results()
            messagebox.showinfo("操作完成", "已清空所有搜索结果")
    
    def save_search_history(self):
        """保存搜索历史"""
        search_text = self.search_text.get().strip()
        search_mode = self.search_mode.get()
        
        history_item = f"[{search_mode}] {search_text}"
        self.search_history.append(history_item)
        
        # 更新历史列表
        with self.ui_lock:
            self.history_listbox.delete(0, tk.END)
            for item in self.search_history[-5:]:  # 只显示最近5条
                self.history_listbox.insert(tk.END, item)
    
    def load_search_history(self, event):
        """加载搜索历史"""
        selection = self.history_listbox.curselection()
        if selection:
            history_item = self.history_listbox.get(selection[0])
            
            # 解析历史项
            mode_start = history_item.find('[') + 1
            mode_end = history_item.find(']')
            search_mode = history_item[mode_start:mode_end]
            search_text = history_item[mode_end + 2:]
            
            # 更新搜索参数
            self.search_mode.set(search_mode)
            self.search_text.set(search_text)
    
    def perform_search(self, search_locations):
        """执行搜索操作"""
        search_text = self.search_text.get()
        search_mode = self.search_mode.get()
        include_subdirs = self.include_subdirs.get()
        case_sensitive = self.case_sensitive.get()
        use_regex = self.use_regex.get()
        file_types = [t.strip() for t in self.file_types.get().split(',') if t.strip()]
        
        # 处理搜索文本
        if not case_sensitive and not use_regex:
            search_text = search_text.lower()
        
        # 编译正则表达式（如果需要）
        regex_pattern = None
        if use_regex:
            try:
                flags = 0 if case_sensitive else re.IGNORECASE
                regex_pattern = re.compile(search_text, flags)
            except re.error as e:
                self.root.after(0, lambda: messagebox.showerror("正则表达式错误", f"无效的正则表达式: {str(e)}"))
                self.search_complete()
                return
        
        # 计算要搜索的文件总数
        self.total_files = self.count_files_to_search(search_locations, include_subdirs, file_types)
        
        # 如果没有文件可搜索，直接完成
        if self.total_files == 0:
            self.root.after(0, lambda: messagebox.showinfo("搜索结果", "没有找到符合条件的文件"))
            self.search_complete()
            return
        
        # 更新状态
        self.update_status()
        
        # 执行搜索
        for location in search_locations:
            if self.stop_event.is_set():
                break
            
            if os.path.isfile(location):
                # 直接搜索单个文件
                self.search_file(location, search_text, search_mode, case_sensitive, use_regex, regex_pattern)
                self.searched_files += 1
                self.update_status()
            else:
                # 搜索目录
                self.search_directory(location, search_text, search_mode, case_sensitive, use_regex, regex_pattern, include_subdirs, file_types)
        
        self.search_complete()
    
    def count_files_to_search(self, locations, include_subdirs, file_types):
        """计算要搜索的文件总数"""
        count = 0
        for location in locations:
            if os.path.isfile(location):
                count += 1
            else:
                for root, _, files in os.walk(location):
                    for file in files:
                        # 检查文件类型过滤
                        if file_types:
                            ext = os.path.splitext(file)[1][1:].lower()
                            if ext not in file_types:
                                continue
                        
                        count += 1
                    
                    if not include_subdirs:
                        break
        return count
    
    def search_directory(self, directory, search_text, search_mode, case_sensitive, use_regex, regex_pattern, include_subdirs, file_types):
        """搜索目录中的文件"""
        try:
            for root, _, files in os.walk(directory):
                if self.stop_event.is_set():
                    return
                
                for file in files:
                    if self.stop_event.is_set():
                        return
                    
                    # 检查文件类型过滤
                    if file_types:
                        ext = os.path.splitext(file)[1][1:].lower()
                        if ext not in file_types:
                            continue
                    
                    file_path = os.path.join(root, file)
                    self.search_file(file_path, search_text, search_mode, case_sensitive, use_regex, regex_pattern)
                    self.searched_files += 1
                    
                    # 每搜索10个文件更新一次进度，平衡性能和实时性
                    if self.searched_files % 10 == 0:
                        self.update_status()
                
                if not include_subdirs:
                    break
        except Exception as e:
            # 忽略无法访问的目录
            pass
    
    def search_file(self, file_path, search_text, search_mode, case_sensitive, use_regex, regex_pattern):
        """搜索单个文件"""
        try:
            if search_mode == "file_name":
                # 搜索文件名
                file_name = os.path.basename(file_path)
                if use_regex:
                    if regex_pattern.search(file_name):
                        self.add_result(file_path, 0, "")
                else:
                    compare_text = file_name if case_sensitive else file_name.lower()
                    if search_text in compare_text:
                        self.add_result(file_path, 0, "")
            else:
                # 搜索文件内容
                try:
                    with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                        for line_num, line in enumerate(f, 1):
                            if self.stop_event.is_set():
                                break
                            
                            if use_regex:
                                if regex_pattern.search(line):
                                    self.add_result(file_path, line_num, line.strip())
                            else:
                                compare_line = line if case_sensitive else line.lower()
                                if search_text in compare_line:
                                    self.add_result(file_path, line_num, line.strip())
                except UnicodeDecodeError:
                    # 尝试其他编码
                    try:
                        with open(file_path, 'r', encoding='latin-1') as f:
                            for line_num, line in enumerate(f, 1):
                                if self.stop_event.is_set():
                                    break
                                
                                if use_regex:
                                    if regex_pattern.search(line):
                                        self.add_result(file_path, line_num, line.strip())
                                else:
                                    compare_line = line if case_sensitive else line.lower()
                                    if search_text in compare_line:
                                        self.add_result(file_path, line_num, line.strip())
                    except:
                        # 无法打开文件
                        pass
        except Exception as e:
            # 忽略无法打开的文件
            pass
    
    def add_result(self, file_path, line_num, content):
        """添加搜索结果"""
        try:
            # 获取文件大小和修改日期
            file_stats = os.stat(file_path)
            file_size = self.format_size(file_stats.st_size)
            modified_time = datetime.fromtimestamp(file_stats.st_mtime).strftime("%Y-%m-%d %H:%M:%S")
            
            self.root.after(0, lambda: self.result_tree.insert("", tk.END, values=(file_path, file_size, modified_time, line_num, content)))
            with self.ui_lock:
                self.results.append((file_path, line_num, content))
        except:
            # 如果获取文件信息失败，仍添加结果
            self.root.after(0, lambda: self.result_tree.insert("", tk.END, values=(file_path, "未知", "未知", line_num, content)))
            with self.ui_lock:
                self.results.append((file_path, line_num, content))
    
    def format_size(self, size_bytes):
        """格式化文件大小显示"""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes/1024:.1f} KB"
        elif size_bytes < 1024 * 1024 * 1024:
            return f"{size_bytes/(1024*1024):.1f} MB"
        else:
            return f"{size_bytes/(1024*1024*1024):.1f} GB"
    
    def update_status(self):
        """更新状态栏信息和进度条"""
        if self.total_files > 0:
            # 计算进度
            progress = min(100.0, (self.searched_files / self.total_files) * 100)
            
            # 计算搜索速度和预计剩余时间
            current_time = datetime.now()
            elapsed_time = (current_time - self.search_start_time).total_seconds()
            update_interval = (current_time - self.last_update_time).total_seconds()
            
            # 避免除以零
            if elapsed_time > 0:
                speed = self.searched_files / elapsed_time
            else:
                speed = 0
                
            # 平滑速度计算，避免波动过大
            if hasattr(self, 'last_speed'):
                speed = (self.last_speed * 2 + speed) / 3
            self.last_speed = speed
            
            # 计算预计剩余时间
            if speed > 0:
                remaining_files = self.total_files - self.searched_files
                estimated_seconds = remaining_files / speed
                
                if estimated_seconds < 60:
                    estimated_time = f"{estimated_seconds:.1f} 秒"
                elif estimated_seconds < 3600:
                    minutes = int(estimated_seconds // 60)
                    seconds = int(estimated_seconds % 60)
                    estimated_time = f"{minutes} 分 {seconds} 秒"
                else:
                    hours = int(estimated_seconds // 3600)
                    minutes = int((estimated_seconds % 3600) // 60)
                    estimated_time = f"{hours} 小时 {minutes} 分"
            else:
                estimated_time = "计算中..."
            
            # 更新UI
            status_text = f"搜索中... 已搜索: {self.searched_files}/{self.total_files} 文件 ({progress:.1f}%), 找到 {len(self.results)} 个结果"
            files_text = f"已搜索: {self.searched_files} 个文件"
            speed_text = f"搜索速度: {speed:.1f} 文件/秒"
            time_text = f"预计剩余时间: {estimated_time}"
            
            # 在主线程中更新UI
            self.root.after(0, lambda: self._update_ui(status_text, progress, files_text, speed_text, time_text))
            
            # 更新最后更新时间
            self.last_update_time = current_time
    
    def _update_ui(self, status_text, progress, files_text, speed_text, time_text):
        """实际更新UI的方法"""
        with self.ui_lock:
            self.status_bar.config(text=status_text)
            self.progress_var.set(progress)
            self.searched_files_var.set(files_text)
            self.search_speed_var.set(speed_text)
            self.estimated_time_var.set(time_text)
    
    def search_complete(self):
        """搜索完成后的处理"""
        self.search_in_progress = False
        
        # 计算总时间
        total_time = (datetime.now() - self.search_start_time).total_seconds()
        
        # 更新状态栏
        if self.stop_event.is_set():
            status_text = f"搜索已取消! 共搜索 {self.searched_files} 个文件，找到 {len(self.results)} 个结果，耗时: {total_time:.1f} 秒"
        else:
            status_text = f"搜索完成! 共搜索 {self.searched_files} 个文件，找到 {len(self.results)} 个结果，耗时: {total_time:.1f} 秒"
        
        # 在主线程中更新UI
        self.root.after(0, lambda: self._search_complete_ui(status_text))
    
    def _search_complete_ui(self, status_text):
        """实际更新搜索完成UI的方法"""
        with self.ui_lock:
            self.status_bar.config(text=status_text)
            
            # 更新按钮状态
            if self.start_button:
                self.start_button.config(state=tk.NORMAL)
            if self.stop_button:
                self.stop_button.config(state=tk.DISABLED)
            
            # 3秒后隐藏进度区域
            self.root.after(3000, lambda: self.progress_frame.pack_forget() if not self.search_in_progress else None)
    
    def open_file(self, event=None):
        """打开文件"""
        try:
            # 获取选中的项
            selected_items = self.result_tree.selection()
            if not selected_items:
                return
                
            for item in selected_items:
                file_path = self.result_tree.item(item, "values")[0]
                
                # 检查文件是否存在
                if not os.path.exists(file_path):
                    messagebox.showwarning("警告", f"文件不存在: {file_path}")
                    continue
                
                # 在Windows上打开文件
                os.startfile(file_path)
        except Exception as e:
            messagebox.showerror("错误", f"无法打开文件: {str(e)}")
    
    def open_file_location(self):
        """打开文件所在位置"""
        try:
            # 获取选中的项
            selected_items = self.result_tree.selection()
            if not selected_items:
                return
                
            for item in selected_items:
                file_path = self.result_tree.item(item, "values")[0]
                
                # 检查文件是否存在
                if not os.path.exists(file_path):
                    messagebox.showwarning("警告", f"文件不存在: {file_path}")
                    continue
                
                directory = os.path.dirname(file_path)
                
                # 在Windows上打开文件位置
                os.startfile(directory)
        except Exception as e:
            messagebox.showerror("错误", f"无法打开文件位置: {str(e)}")
    
    def delete_file(self):
        """删除文件"""
        try:
            # 获取选中的项
            selected_items = self.result_tree.selection()
            if not selected_items:
                return
                
            # 确认删除
            count = len(selected_items)
            if count == 1:
                file_path = self.result_tree.item(selected_items[0], "values")[0]
                file_name = os.path.basename(file_path)
                if not messagebox.askyesno("确认删除", f"确定要删除文件 '{file_name}' 吗?\n此操作不可恢复!"):
                    return
            else:
                if not messagebox.askyesno("确认删除", f"确定要删除选中的 {count} 个文件吗?\n此操作不可恢复!"):
                    return
                
            # 执行删除
            for item in selected_items:
                file_path = self.result_tree.item(item, "values")[0]
                
                # 检查文件是否存在
                if not os.path.exists(file_path):
                    messagebox.showwarning("警告", f"文件不存在: {file_path}")
                    continue
                
                try:
                    os.remove(file_path)
                    self.result_tree.delete(item)
                except Exception as e:
                    messagebox.showerror("错误", f"无法删除文件 '{os.path.basename(file_path)}': {str(e)}")
            
            messagebox.showinfo("操作完成", f"已成功删除 {count} 个文件")
        except Exception as e:
            messagebox.showerror("错误", f"删除文件时出错: {str(e)}")
    
    def copy_file_path(self):
        """复制文件路径到剪贴板"""
        try:
            # 获取选中的项
            selected_items = self.result_tree.selection()
            if not selected_items:
                return
                
            # 复制文件路径
            paths = [self.result_tree.item(item, "values")[0] for item in selected_items]
            
            # 清空剪贴板并设置新内容
            self.root.clipboard_clear()
            self.root.clipboard_append("\n".join(paths))
            
            messagebox.showinfo("操作完成", f"已复制 {len(paths)} 个文件路径到剪贴板")
        except Exception as e:
            messagebox.showerror("错误", f"复制文件路径时出错: {str(e)}")

if __name__ == "__main__":
    # 确保中文显示正常
    import matplotlib
    matplotlib.use('TkAgg')
    
    root = tk.Tk()
    app = FileSearchTool(root)
    root.mainloop()